use std::sync::{Arc, Condvar, Mutex, MutexGuard, RwLock};
use std::thread;
use std::thread::{sleep, spawn};
use std::time::Duration;

use lazy_static::lazy_static;
use tokio::sync::Semaphore;

use crate::gen_title;

pub fn ch4_14_1() {
    gen_title("ch4_14_1", 18);

    let m = Mutex::new(5);

    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }

    println!("m = {:?}", m);
}

pub fn ch4_14_2() {
    gen_title("ch4_14_2", 18);

    let m = Mutex::new(5);

    let mut num = m.lock().unwrap();
    *num = 6;
    drop(num);

    let mut num1 = m.lock().unwrap();
    *num1 = 7;
    drop(num1);

    println!("m = {:?}", m);
}

pub fn ch4_14_3() {
    gen_title("ch4_14_3", 18);

    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            println!("{}", num);
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

pub fn ch4_14_4() {
    gen_title("ch4_14_4", 18);

    lazy_static! {
        static ref MUTEX1: Mutex<i64> = Mutex::new(0);
        static ref MUTEX2: Mutex<i64> = Mutex::new(0);
    }

    let mut children = vec![];

    for i_thread in 0..2 {
        children.push(thread::spawn(move || {
            for _ in 0..1 {
                if i_thread % 2 == 0 {
                    let guard: MutexGuard<i64> = MUTEX1.lock().unwrap();

                    println!("线程 {} 锁住了 MUTEX1, 接着准备去锁 MUTEX2!", i_thread);

                    drop(guard);
                    sleep(Duration::from_millis(10));

                    let guard = MUTEX2.lock().unwrap();
                } else {
                    let _guard = MUTEX2.lock().unwrap();
                    println!("线程 {} 锁住了 MUTEX2, 接着准备去锁 MUTEX1!", i_thread);

                    let _guard = MUTEX1.lock().unwrap();
                }
            }
        }));
    }

    for child in children {
        let _ = child.join();
    }

    println!("死锁没有发生");
}

pub fn ch4_14_5() {
    gen_title("ch4_14_5", 18);

    lazy_static! {
        static ref MUTEX1: Mutex<i64> = Mutex::new(0);
        static ref MUTEX2: Mutex<i64> = Mutex::new(0);
    }

    let mut children = vec![];

    for i_thread in 0..2 {
        children.push(thread::spawn(move || {
            for _ in 0..1 {
                if i_thread % 2 == 0 {
                    let guard = MUTEX1.lock().unwrap();

                    println!("线程 {} 锁住了 MUTEX1, 接着准备去锁 MUTEX2!", i_thread);

                    sleep(Duration::from_millis(10));

                    let guard = MUTEX2.try_lock();
                    println!(
                        "线程 {} 尝试去锁 MUTEX2, 结果是 {}",
                        i_thread,
                        guard.is_ok()
                    );
                } else {
                    let _guard = MUTEX2.lock().unwrap();

                    println!("线程 {} 锁住了 MUTEX2, 接着准备去锁 MUTEX1!", i_thread);
                    sleep(Duration::from_millis(10));
                    let guard = MUTEX1.try_lock();
                    println!(
                        "线程 {} 尝试去锁 MUTEX1, 结果是 {}",
                        i_thread,
                        guard.is_ok()
                    );
                }
            }
        }))
    }

    for child in children {
        let _ = child.join();
    }

    println!("死锁没有发生");
}

pub fn ch4_14_6() {
    gen_title("ch4_14_6", 18);

    let lock = RwLock::new(5);

    {
        let r1 = lock.read().unwrap();
        let r2 = lock.read().unwrap();
        assert_eq!(*r1, 5);
        assert_eq!(*r2, 5);
        println!("r1 and r2 are both available.");
    }

    {
        let mut w = lock.write().unwrap();
        *w += 1;
        assert_eq!(*w, 6);
        println!("w available.");
    }
}

pub fn ch4_14_7() {
    gen_title("ch4_14_7", 18);

    let flag = Arc::new(Mutex::new(false));
    let cond = Arc::new(Condvar::new());
    let cflag = flag.clone();
    let ccond = cond.clone();

    let hdl = spawn(move || {
        let mut lock = cflag.lock().unwrap();
        let mut counter = 0;

        while counter < 3 {
            while !*lock {
                lock = ccond.wait(lock).unwrap();
            }

            *lock = false;

            counter += 1;
            println!("inner counter: {}", counter);
        }
    });

    let mut counter = 0;
    loop {
        sleep(Duration::from_millis(10));
        *flag.lock().unwrap() = true;
        counter += 1;
        if counter > 3 {
            break;
        }
        println!("outer counter: {}", counter);
        cond.notify_one();
    }

    hdl.join().unwrap();
    println!("{:?}", flag);
}

pub async fn ch4_14_8() {
    gen_title("ch4_14_8", 18);

    let semaphore = Arc::new(Semaphore::new(3));
    let mut join_handles = Vec::new();

    for _ in 0..5 {
        let permit = semaphore.clone().acquire_owned().await.unwrap();
        join_handles.push(tokio::spawn(async move {
            println!("{:?}", permit);
            drop(permit);
        }));
    }

    for handle in join_handles {
        handle.await.unwrap();
    }
}
